#!/usr/bin/env perl

# 
# Copyright (c) 2002-2007 Eric Wallengren
# This file is part of the Continuous Automated Build and Integration 
# Environment (CABIE)
# 
# CABIE is distributed under the terms of the GNU General Public
# License version 2 or any later version.  See the file COPYING for copying 
# permission or http://www.gnu.org. 
#                                                                            
# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR  
# IMPLIED, without even the implied warranty of MERCHANTABILITY or FITNESS 
# FOR A PARTICULAR PURPOSE.  ANY USE IS AT YOUR OWN RISK. 
#                                                                            
# Permission to modify the code and to distribute modified code is granted, 
# provided the above notices are retained, and a notice that the code was 
# modified is included with the above copyright notice. 
# 

#
# Rewrite of mailer to be more modular supporting remote 
# perforce servers
#

my $POSIX = 1;

my $ospackage;

#
# See if this is a windoz system...
#
if ($^O =~ /MSWin32/) {
    $POSIX = 0;
    $ospackage = "winsys";
} else {
    $ospackage = "unixsys";
}

BEGIN {
    push @INC, "lib";
    push @INC, "../lib";
    push @INC, "../../lib";
}

#
# Standard Perl packages
#
use strict;
no  strict "refs";
use Getopt::Std;
use Cwd;
use Sys::Hostname;
use HTML::Entities;
use Mail::Sendmail;

#
# Get hostname
#
my $hostname = hostname();
$hostname    =~ s/\.[a-zA-Z0-9]+//g;

my $configname = $hostname;
$configname    =~ s/-//g;

#
# Buildserver specific packages
#
use Bldsvr;
require "$configname.pm";

#
# Use winsys for M$
#
require "$ospackage.pm";

my $dir = cwd();

unshift (@INC, "$dir/lib");

#
# Call CM broker
#
use cmbroker;
my $cmbroker = new cmbroker;

#
# Use winsys for M$
#
my $os     = new $ospackage;
my $config = new $configname;

my %mail;

#
# Grab configuration information from server
#
$mail{From}  = $config->NOTIFYFROM;
$mail{Smtp}  = $config->SMTP;
$mail{'content-type'} = 'text/html; charset=iso-8859.1"';

#
# get current dir
#
my $dir = cwd();

my %Options;

#
# Use lib from buildserver
#
unshift (@INC, "$dir/lib"); # Prepend a directory name

open (MAILDBG, ">$dir/logs/maildbg.log");

getopt('n:t:j:s:', \%Options);

#
# We got past that, get job properties
#
my $buildname = $Options{n};
my $buildtype = $Options{t};
my $buildnum  = $Options{j};
my $buildstat = $Options{s};

if (!defined($buildname) || !defined($buildtype)
    || !defined($buildnum) || !defined($buildstat)) {
    usage();
} 

_logger("$buildname $buildtype $buildnum $buildstat");

#
# declare build vars
#
my $port;
my $client;
my $top;
my $type;
my $sccs;
my $browserlink;

#
# Declare hash variables
#
my %emailhash;
my %emailbchash;
my %emptyhash;

#
# Declare mail variables
#
my $subject;
my @message;
my @tousers;
my @bctousers;
my $heading;
my $key;
my $address;
my $line;

#
# Get configuraton information
#
my $TmpDir     = $config->BTMP;
my $WriteDir   = $config->JOBDIR;
my $Company    = $config->COMPANY;
my $Webserver  = $config->WEBSERVER;
my $Notifyall  = $config->NOTIFYALL;
my $Globmail   = $config->GLOBMAIL;
my $Admin      = $config->ADMIN;
my $Delim      = $config->SMTPDELIM;
my $failall    = $config->FAILALL;
my $serverroot = $config->BSR;

#
# Set default boolean values
#
my $Globfail  = 0;
my $Spamon    = 0;
my $bSendMail = 1;

#
# Set tempdir (for all platfoms)
#
$ENV{"TMPDIR"}="$TmpDir";
$ENV{"TEMP"}  ="$TmpDir";
$ENV{"TMP"}   ="$TmpDir";

#
# Globally read job roperties...
#
if (!_getjobproperties($buildname)) {
    print STDERR "no job $buildname!\n";
    exit 1;
}

#
# Log messages
#
_logger("got job properties");

my $geohead;
my $geotail;

#
# Set default messages
#
if ($buildstat =~ "failed") {
    $Globfail      = 1;
    $mail{Subject} = "*BUILDBREAKER* $buildname $buildnum $buildtype ".
                     "build failed";
    $heading       = "$buildname $buildnum build failed!";
    $geohead       = "$buildname $buildnum build failed!";
    $geotail       = "$buildname failed!";
} else {
    $mail{Subject} = "$buildname $buildnum build completed";
    $geohead       = "$buildname $buildnum build completed";
    $geotail       = "$buildname completed";
    $heading       = "$buildname $buildnum is available from it's ".
                     "<a href=\"$Webserver/$hostname/$buildname/".
                     "$buildnum/\">output directory</a>";
}

my $geomessage = _gengeomessage("$geohead", "$geotail");

push (@message, "<p>$geomessage");

push (@message, "<p>$heading");

_logger("heading will be $heading");

my $logs = "Logfiles are available from the ".
           "<a href=\"$Webserver/$hostname/$buildname/$buildnum/\"".
           ">build output directory</a>";

_logger("going to add subscribers");

#
# Generate list of subscribers
#
_addsubscribers($buildname);

my $sccscommand = $sccs."_client";

my $realclient = $cmbroker->$sccscommand($client);

my $what;

if ($sccs =~ /perforce/ic) {
    $what = "client";
}

if ($sccs =~ /cvs/ic) {
    $what = "module(s)";
}

if ($sccs =~ /subversion/ic) {
    $what = "module(s)";
}

push @message, "<p>Files checked out from $port using $what $realclient:".
               "<br><br>";

#
# Call function to populate mailer hashes for this particular job
#
my @changes = genchanges($buildname, $port, $realclient,
                         $top, $sccs, $browserlink);

#
# Create an html representation of changes made to the tree
# since the '.log' extension doesn't open an editor by default
#
open(HTM, ">$WriteDir/$buildname/$buildnum/$buildname.update.html");

print HTM "<html><head><title>Changes for $buildname $buildnum</title>".
           "</head><body><h2>Changes for $buildname $buildnum</h2><br><pre>";


push @message, "<pre>\n";
foreach my $line (@changes) {
    print HTM $line;
    push (@message, "$line");
}

#
# Write each entry to the html file
#
# push (@message, "\n");

print HTM "</pre></body></html>";

#
# Close the html file
#
close(HTM);

foreach $address (keys %emailhash) {
    push (@tousers, $address);
}

foreach $address (keys %emailbchash) {
    push (@bctousers, $address);
}

_logger( "$subject" );

push (@message, "\n$logs\n");

if (-f "$dir/config/$hostname.disclaimer") {
    open (DISC, "<$dir/config/$hostname.disclaimer");
    my @Disclaimer = <DISC>;
    close(DISC);
    foreach $line (@Disclaimer) {
        push (@message, $line);
    }
    push @message, "</pre>\n";
}

open (F, ">$TmpDir/$buildname.mail");
foreach $line (@message) {
    print F $line;
}
close (F);

open (MSG, "<$TmpDir/$buildname.mail");
foreach $line (<MSG>) {
    $mail{Message} .= $line;
}
close (MSG);


foreach $line (@tousers) {
    $mail{To} .= "$line$Delim";
}

foreach $line (@bctousers) {
    $mail{Bcc} .= "$line$Delim";
}

#
# If the build failed sequentially - from .bad file
# see if the server is set to send multiple spams...
#
if ($Globfail && -f "$serverroot/logs/$buildname.bad" ) {

    #
    # if global failure spam is set to 0
    #
    if (! $failall) {
        $bSendMail = 0;
    }
}

if ($bSendMail) {

    sendmail %mail;

    if ($Mail::Sendmail::error) {
        $mail{To} = "$Admin";
        $mail{Message} = "content of ".
                         "\$Mail::Sendmail::error:\n$Mail::Sendmail::error\n";
        $mail{Subject} = "*Failed to deliver email* $buildname $buildnum ".
                         "$buildtype ";
        sendmail %mail;

    }
}

close(MAILDBG);

#
# Add the list of subscribers to the emailhash
#
sub _addsubscribers() {

    my $name = shift;
    my @subscribers;
    my $entry;

    #
    # SQL Stuff...
    #
    my $sqlquery;
    my @sqlarray;
    my @spamarray;

    _logger("_addsubscribers using SQL");

    #
    # Always notify build admin
    #
    _addemailhash($Admin, 1);

    #
    # If all users need to be notified of a build failure
    #
    if ($Notifyall && $Globfail) {

        _logger("_addsubscribers notifyall and globfail");

        #
        # Get general spam setting
        #
        $sqlquery = "select spam from configuration where ".
                    "server=\"$hostname\" and title=\"$name\"";

        _logger("_addsubscribers $sqlquery");

        @spamarray  = $os->run_sql_query("$sqlquery", ";", 0);

        #
        # If spam is on for the build add global email address
        # to the mail hash
        #
        if ($spamarray[0]) {
            $Spamon = 1;
            _logger("_addsubscribers adding $Globmail 0");
            _addemailhash($Globmail, 0);
        } else {
           
            #
            # Spam is not set for this build, get subscribers
            #
            $sqlquery = "select address from subscription ".
                        "where server=\"$hostname\" and title=\"$name\" ".
                        "order by address";

            _logger("_addsubscribers $sqlquery if not spamarray");

            @sqlarray  = $os->run_sql_query("$sqlquery", ";", 0);

            #
            # Add any subscribers found
            #
            foreach $entry (@sqlarray) {
                chomp $entry;
                _logger("_addsubscribers adding $entry 1");
                _addemailhash($entry, 1);
            }
        } 
        
     } else {

        #
        # This is a good build, just add subscribers initially
        #
        _logger("_addsubscribers !notifyall or !globfail");

        $sqlquery = "select address from subscription ".
                    "where server=\"$hostname\" and title=\"$name\" ".
                    "order by address";

        @sqlarray  = $os->run_sql_query("$sqlquery", ";", 0);

        foreach $entry (@sqlarray) {
            chomp $entry;
            _addemailhash($entry, 1);
        }
    }

}

#
# Parse sync log, generate changelist, user, and email info
#
sub genchanges() {

    my $name      = shift;
    my $port      = shift;
    my $client    = shift;
    my $root      = shift;
    my $sccs      = shift;
    my $formatted = shift;

    my $sccscommand;

    my @synclist;

    my $href = \%emailhash;

    _logger( "genchanges changing dir to $root" );

    $sccscommand = $sccs."_lastcheckout";

    @synclist = $cmbroker->$sccscommand($port, $client, $root, $name, 
                              $buildnum, $formatted, $href);

    return @synclist;

    
}

sub usage {

    print "usage: \n\n";
    print "\t-n jobname\n";
    print "\t-j jobnumber\n";
    print "\t-t type [debug|retail]\n";
    print "\t-s status [passed|failed]\n\n";
    
    exit 1;

}

#
# Add email addresses to hash in order to help aviod duplicate addresses
#
sub _addemailhash() {

    my $emailaddress = shift;
    my $type         = shift;

    _logger("addemailhash $emailaddress $type");

    #
    # If this is a bcc address
    #
    if ($type) {
        $emailbchash{"$emailaddress"} = "";
    } else {
        $emailhash{"$emailaddress"} = "";
    }

}

#
# Get job properties for this build
#
sub _getjobproperties() {

    my $job = shift;
    my $Found;
    my @JobDesc;

    #
    # SQL Stuff...
    #
    my $sqlquery;
    my @sqlarray;
    my $ret;


    $sqlquery  = "select port, client, top, type, sccs, browserlink ".  
                 "from configuration where server=\"$hostname\" ".
                 "and title=\"$job\"";

    @sqlarray  = $os->run_sql_query("$sqlquery", ";", 0);

    $ret = @sqlarray;

    ($port, $client, $top, $type, $sccs, $browserlink) = 
        split(/;/, @sqlarray[0]);

    return $ret;

}

sub _logger {

    my $string = shift;

    my $reqtime = scalar localtime;

    print MAILDBG "[$reqtime]: $string\n";

}

#
#  Just for fun....
#
sub _gengeomessage {
 
    my $string   = shift;
    my $linkname = shift;
    
    my $message="<a href=http://www.geogreeting.com/view.html?z";

    my $entry;
    my @array;

    my %alphahash = (
    
        a => 'b',
        b => 'c',
        c => 'd',
        d => 'e',
        e => 'f',
        f => 'g',
        g => 'h',
        h => 'i',
        i => 'j',
        j => 'k',
        k => 'l',
        l => 'm',
        m => 'n',
        n => 'o',
        o => 'p',
        p => 'q',
        q => 'r',
        r => 's',
        s => 't',
        t => 'u',
        u => 'v',
        v => 'w',
        w => 'x',
        x => 'y',
        y => 'z',
        z => 'A',
        0 => 'B',
        1 => 'C',
        2 => 'D',
        3 => 'E',
        4 => 'F',
        5 => 'G',
        6 => 'H',
        7 => 'I',
        8 => 'J',
        9 => 'K',
        '!' => '1',
        '.' => 'U',
        '_' => 'X',
        '-' => 'Y',
    
    );
    
    @array = split(//, lc($string));
    
    foreach $entry (@array) {
    
       if ($entry =~ / /) {
           $message .= "L+";
       } else {
           $message .= "$alphahash{$entry}+";
       }
    }
    
    $message =~ s/\+$//g;

    $message .= ">$linkname</a>";
    
    return $message;

}
